#include <iostream>

#include "jobqueue.h"
#include "util.h"
using namespace std;

uint64 size = 500000000ll;
uint64 * a;
JobQueue jq;
int num_threads = 100;
int num_tasks = 10000;
uint64 N = 1000000000;

uint64 threenp1(uint64 i) {
  uint64 ret = 0;
  while ( (i > 1) && (i < 0x1000000000000000ll)) {
    if (i % 2) i = 3 * i + 1;
    else i /= 2;
    ret++;
  }
  return ret;
}

void SimpleZero() {
  bzero(a, size * sizeof(uint64));
}

struct ZeroTask : public JobQueue::Task {
  uint64 begin_;
  uint64 end_;  
  void Run() {
    bzero(a+begin_, (end_-begin_) * sizeof(uint64));
  }
};

struct ComputeTask : public JobQueue::Task {
  //uint64 *A;
  //ComputeTask() {A = a;}
  uint64 begin_;
  uint64 end_;  
  void Run() {
    // uint64 * A = a;
    for (uint64 i=begin_; i<end_; i++) {
      if (i && (N % i == 0)) cout << i << " divides " << N << endl;
    }
  }
};

void JobQueueZero() {
  JobQueue::Job j(&jq);
  for (uint64 i=0; i<num_tasks; i++) {
    ZeroTask * t = new ZeroTask;
    t->begin_ = (size * i) / num_tasks;
    t->end_ = (size * (i+1)) / num_tasks;
    j.AddTask(t);
  }
  j.Wait();
}

void JobQueueCompute() {
  JobQueue::Job j(&jq);
  for (uint64 i=0; i<num_tasks; i++) {
    ComputeTask * t = new ComputeTask;
    t->begin_ = (N * i) / num_tasks;
    t->end_ = (N * (i+1)) / num_tasks;
    j.AddTask(t);
  }
  j.Wait();
}

int main() {
  // a = new uint64[size];
  jq.LaunchThreads(num_threads);
  cout << "About to zero out" << endl;
  //sleep(1);
  // SimpleZero();
  // cout << "finished initial zero out " << endl;
  ResetMilli();
  //SimpleZero();
  //JobQueueZero();
  JobQueueCompute();
  PrintElapsedTime2();
  cout << "Finished" << endl;
  /*for (uint64 i=0; i<size; i++) {
    if (a[i] != i * 499999500000ll) {
      cout << "error" << endl;
      return 1;
    }
  }
  cout << "size = " << size << endl;
  cout << "All checks out " << endl;*/
  return 1;
}
